# app1/routes_patrol_board.py
from flask import request
from flask_restx import Namespace, Resource, fields
from flask_jwt_extended import jwt_required
from sqlalchemy import func, distinct
from datetime import datetime, timedelta

from app1 import db
from app1.models import KmsAppInfo, PatrolAppConfig, PatrolAppDef
from app1.utils import format_response  # 检查这个函数的实际参数

# 复用 routes_patrol.py 中的文件扫描工具函数
import os
import re
import stat

# 创建命名空间
ns_patrol_board = Namespace('patrol_board', description='巡检驾驶舱数据统计')


# ========================== 工具函数（复用 routes_patrol.py） ==========================
def scan_files(dir_path, pattern):
    """
    返回目录下【文件名含 pattern】的文件绝对路径列表（正则）
    """
    if not os.path.isdir(dir_path):
        return []
    # 预编译正则，忽略大小写
    pat = re.compile(pattern, re.I)
    matched = []
    for name in os.listdir(dir_path):
        if pat.search(name):
            matched.append(os.path.join(dir_path, name))
    return matched


def get_latest_file(files):
    """
    获取文件列表中修改时间最新的文件
    """
    if not files:
        return None
    return max(files, key=lambda f: os.path.getmtime(f))


# ========================== 数据模型定义 ==========================
target_stats_model = ns_patrol_board.model('TargetStats', {
    'apps': fields.Integer(description='应用系统总数'),
    'patrol_files': fields.Integer(description='巡检文件总数（每个应用最后一次产生的文件）'),
    'patrol_config': fields.Integer(description='巡检配置总数'),
    'patrol_def': fields.Integer(description='应用定义总数')
})

board_summary_model = ns_patrol_board.model('BoardSummary', {
    'targetStats': fields.Nested(target_stats_model, description='目标统计数据'),
    'recentPatrols': fields.List(fields.Raw, description='最近巡检记录'),
    'healthStatus': fields.Raw(description='健康状态统计')
})

# 响应模型
response_board_model = ns_patrol_board.model('ResponseBoard', {
    'message': fields.Nested(ns_patrol_board.model('MessageBoard', {
        'result': fields.Integer(description='0=成功 1=失败'),
        'result_text': fields.String(description='结果描述'),
        'data': fields.Nested(board_summary_model)
    }))
})

# 简单的响应模型
simple_response_model = ns_patrol_board.model('SimpleResponse', {
    'message': fields.Nested(ns_patrol_board.model('SimpleMessage', {
        'result': fields.Integer(description='0=成功 1=失败'),
        'result_text': fields.String(description='结果描述'),
        'data': fields.Raw(description='返回数据')
    }))
})

# 在数据模型定义部分添加以下模型

# 应用系统概览项模型
system_overview_item_model = ns_patrol_board.model('SystemOverviewItem', {
    'id': fields.String(required=True, description='服务目录编号'),
    'name': fields.String(required=True, description='服务名称'),
    # 'inspectionDate': fields.String(description='巡检文件产生时间'),
    # 'fileName': fields.String(description='巡检文件名'),
    # 'status': fields.String(required=True, description='状态: completed/waiting'),
    'color': fields.String(required=True, description='颜色代码'),
    # 'fileSize': fields.String(description='文件大小'),
    'remark': fields.String(description='备注'),
    'type': fields.String(required=True, description='系统类型'),
    'level': fields.Integer(required=True, description='级别 1-5'),
    'patrol_names': fields.List(fields.String, description='巡检配置名称数组')
})

# 应用系统概览列表模型
system_overview_list_model = ns_patrol_board.model('SystemOverviewList', {
    'systems': fields.List(fields.Nested(system_overview_item_model), description='应用系统列表')
})

# 应用系统概览响应模型
system_overview_response_model = ns_patrol_board.model('SystemOverviewResponse', {
    'message': fields.Nested(ns_patrol_board.model('SystemOverviewMessage', {
        'result': fields.Integer(description='0=成功 1=失败'),
        'result_text': fields.String(description='结果描述'),
        'data': fields.Nested(system_overview_list_model)
    }))
})

# ========================== 数据模型定义 ==========================

# 在现有的数据模型定义后面添加以下模型

# 主图小球项目模型
main_ball_item_model = ns_patrol_board.model('MainBallItem', {
    'devDepartment': fields.String(required=True, description='开发部门'),
    'total': fields.Integer(required=True, description='部门应用总数'),
    'exception': fields.Integer(required=True, description='异常数量')
})

# 主图小球概览模型
main_ball_overview_model = ns_patrol_board.model('MainBallOverview', {
    'mainDepartment': fields.String(required=True, description='主维护部门'),
    'total': fields.Integer(required=True, description='应用总数')
})

# 主图小球数据模型
main_ball_data_model = ns_patrol_board.model('MainBallData', {
    'overview': fields.Nested(main_ball_overview_model, description='概览信息'),
    'item': fields.List(fields.Nested(main_ball_item_model), description='部门明细列表')
})

# 主图小球响应模型
main_ball_response_model = ns_patrol_board.model('MainBallResponse', {
    'message': fields.Nested(ns_patrol_board.model('MainBallMessage', {
        'result': fields.Integer(description='0=成功 1=失败'),
        'result_text': fields.String(description='结果描述'),
        'data': fields.Nested(main_ball_data_model)
    }))
})

# ========================== 数据模型定义 ==========================

# 在现有的数据模型定义后面添加以下模型

# 主图HA等级排名项模型
ha_rank_item_model = ns_patrol_board.model('HaRankItem', {
    'title': fields.String(required=True, description='HA等级'),
    'value': fields.Integer(required=True, description='数量')
})

# 主图HA等级排名响应模型
ha_rank_response_model = ns_patrol_board.model('HaRankResponse', {
    'message': fields.Nested(ns_patrol_board.model('HaRankMessage', {
        'result': fields.Integer(description='0=成功 1=失败'),
        'result_text': fields.String(description='结果描述'),
        'data': fields.List(fields.Nested(ha_rank_item_model))
    }))
})


# ========================== 核心业务逻辑 ==========================
def get_target_stats():
    """
    获取四个核心指标数据
    """
    try:
        # 1. 应用系统总数 - 从 kms_app_info 表
        apps_count = db.session.query(func.count(KmsAppInfo.service_catalog)).scalar() or 0

        # 2. 巡检配置总数 - 从 patrol_app_config 表
        patrol_config_count = db.session.query(func.count(PatrolAppConfig.id)).scalar() or 0

        # 3. 应用定义总数 - 从 patrol_app_def 表
        patrol_def_count = db.session.query(func.count(PatrolAppDef.id)).scalar() or 0

        # 4. 巡检文件总数（每个应用最后一次产生的文件）
        patrol_files_count = calculate_patrol_files_count()

        return {
            'apps': apps_count,
            'patrol_files': patrol_files_count,
            'patrol_config': patrol_config_count,
            'patrol_def': patrol_def_count
        }

    except Exception as e:
        print(f"获取目标统计数据失败: {str(e)}")
        return {
            'apps': 0,
            'patrol_files': 0,
            'patrol_config': 0,
            'patrol_def': 0
        }


def calculate_patrol_files_count():
    """
    计算巡检文件总数：每个巡检配置取最后一个匹配的文件
    """
    try:
        # 获取所有巡检配置
        configs = PatrolAppConfig.query.all()
        if not configs:
            return 0

        root_dir = os.getenv('PATROL_PATH', r'/HX/HX')
        if not os.path.isdir(root_dir):
            print(f"目录不存在: {root_dir}")
            return 0

        valid_config_count = 0

        for config in configs:
            # 扫描匹配的文件
            files = scan_files(root_dir, config.match_alias)
            if files:
                # 每个配置只取最后一个文件（最新文件）
                latest_file = get_latest_file(files)
                if latest_file and os.path.isfile(latest_file):
                    valid_config_count += 1

        return valid_config_count

    except Exception as e:
        print(f"计算巡检文件总数失败: {str(e)}")
        return 0


def get_recent_patrols(limit=10):
    """
    获取最近的巡检记录
    """
    try:
        recent_patrols = PatrolAppDef.query.order_by(
            PatrolAppDef.create_time.desc()
        ).limit(limit).all()

        result = []
        for patrol in recent_patrols:
            result.append({
                'id': patrol.id,
                'app_name': patrol.app_name,
                'app_name_short': patrol.app_name_short,
                'app_type': patrol.app_type,
                'app_status': patrol.app_status,
                'create_time': patrol.create_time.isoformat() if patrol.create_time else None,
                'update_time': patrol.update_time.isoformat() if patrol.update_time else None
            })

        return result

    except Exception as e:
        print(f"获取最近巡检记录失败: {str(e)}")
        return []


def get_health_status():
    """
    获取健康状态统计
    """
    try:
        # 统计各状态的应用数量
        status_stats = db.session.query(
            KmsAppInfo.importance_grade,  # 使用重要性分级作为状态
            func.count(KmsAppInfo.service_catalog)
        ).group_by(KmsAppInfo.importance_grade).all()

        # 统计启用/停用的应用定义
        active_apps = PatrolAppDef.query.filter_by(app_status=True).count()
        inactive_apps = PatrolAppDef.query.filter_by(app_status=False).count()

        # 今日新增记录
        today_start = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
        today_configs = PatrolAppConfig.query.filter(
            PatrolAppConfig.create_time >= today_start
        ).count()

        today_defs = PatrolAppDef.query.filter(
            PatrolAppDef.create_time >= today_start
        ).count()

        return {
            'status_distribution': dict(status_stats),
            'active_apps': active_apps,
            'inactive_apps': inactive_apps,
            'today_configs': today_configs,
            'today_defs': today_defs,
            'total_app_defs': active_apps + inactive_apps
        }

    except Exception as e:
        print(f"获取健康状态统计失败: {str(e)}")
        return {
            'status_distribution': {},
            'active_apps': 0,
            'inactive_apps': 0,
            'today_configs': 0,
            'today_defs': 0,
            'total_app_defs': 0
        }


# ========================== API 接口 ==========================
@ns_patrol_board.route('/summary')
class PatrolBoardSummary(Resource):
    @ns_patrol_board.doc(description='获取巡检驾驶舱概览数据')
    @ns_patrol_board.marshal_with(response_board_model)
    # @jwt_required()
    def get(self):
        """获取巡检驾驶舱概览数据"""
        try:
            # 获取四个核心指标
            target_stats = get_target_stats()

            # 获取最近巡检记录
            recent_patrols = get_recent_patrols(limit=10)

            # 获取健康状态统计
            health_status = get_health_status()

            data = {
                'targetStats': target_stats,
                'recentPatrols': recent_patrols,
                'healthStatus': health_status
            }

            return {
                'message': {
                    'result': 0,
                    'result_text': '获取驾驶舱数据成功',
                    'data': data
                }
            }

        except Exception as e:
            return {
                'message': {
                    'result': 1,
                    'result_text': f'获取驾驶舱数据失败: {str(e)}',
                    'data': None
                }
            }, 500


@ns_patrol_board.route('/target_stats')
class TargetStatsResource(Resource):
    @ns_patrol_board.doc(description='获取四个核心目标统计数据')
    @ns_patrol_board.marshal_with(simple_response_model)
    # @jwt_required()
    def get(self):
        """专门获取四个核心目标统计数据"""
        try:
            target_stats = get_target_stats()

            return {
                'message': {
                    'result': 0,
                    'result_text': '获取目标统计数据成功',
                    'data': target_stats
                }
            }

        except Exception as e:
            return {
                'message': {
                    'result': 1,
                    'result_text': f'获取目标统计数据失败: {str(e)}',
                    'data': None
                }
            }, 500


@ns_patrol_board.route('/app_status_overview')
class AppStatusOverviewResource(Resource):
    @ns_patrol_board.doc(description='获取应用状态概览')
    @ns_patrol_board.marshal_with(simple_response_model)
    # @jwt_required()
    def get(self):
        """获取应用状态分布概览"""
        try:
            # 应用重要性分级统计
            importance_stats = db.session.query(
                KmsAppInfo.importance_grade,
                func.count(KmsAppInfo.service_catalog).label('count')
            ).group_by(KmsAppInfo.importance_grade).all()

            # 应用可用性级别统计
            ha_stats = db.session.query(
                KmsAppInfo.ha_grade,
                func.count(KmsAppInfo.service_catalog).label('count')
            ).group_by(KmsAppInfo.ha_grade).all()

            # 应用定义类型统计
            app_type_stats = db.session.query(
                PatrolAppDef.app_type,
                func.count(PatrolAppDef.id).label('count')
            ).group_by(PatrolAppDef.app_type).all()

            data = {
                'importance_distribution': [
                    {'grade': grade, 'count': count}
                    for grade, count in importance_stats if grade
                ],
                'ha_distribution': [
                    {'grade': grade, 'count': count}
                    for grade, count in ha_stats if grade
                ],
                'app_type_distribution': [
                    {'type': app_type, 'count': count}
                    for app_type, count in app_type_stats
                ]
            }

            return {
                'message': {
                    'result': 0,
                    'result_text': '获取应用状态概览成功',
                    'data': data
                }
            }

        except Exception as e:
            return {
                'message': {
                    'result': 1,
                    'result_text': f'获取应用状态概览失败: {str(e)}',
                    'data': None
                }
            }, 500


@ns_patrol_board.route('/config_details')
class ConfigDetailsResource(Resource):
    @ns_patrol_board.doc(description='获取巡检配置详情')
    @ns_patrol_board.marshal_with(simple_response_model)
    # @jwt_required()
    def get(self):
        """获取巡检配置的详细信息"""
        try:
            # 获取所有巡检配置
            configs = PatrolAppConfig.query.all()

            config_details = []
            root_dir = os.getenv('PATROL_PATH', r'/HX/HX')

            for config in configs:
                files = scan_files(root_dir, config.match_alias)
                latest_file = get_latest_file(files) if files else None

                config_details.append({
                    'id': config.id,
                    'patrol_name': config.patrol_name,
                    'app_name': config.app_name,
                    'match_alias': config.match_alias,
                    'file_count': len(files),
                    'latest_file': latest_file,
                    'has_latest_file': latest_file is not None
                })

            return {
                'message': {
                    'result': 0,
                    'result_text': '获取配置详情成功',
                    'data': config_details
                }
            }

        except Exception as e:
            return {
                'message': {
                    'result': 1,
                    'result_text': f'获取配置详情失败: {str(e)}',
                    'data': None
                }
            }, 500


@ns_patrol_board.route('/summary_app_overview')
class SummaryAppOverviewResource(Resource):
    @ns_patrol_board.doc(description='获取应用系统概览列表')
    @ns_patrol_board.marshal_with(system_overview_response_model)
    # @jwt_required()
    def get(self):
        """获取应用系统概览列表，包含巡检配置信息"""
        try:
            # 获取所有应用系统
            apps = KmsAppInfo.query.all()

            systems = []

            # 颜色映射：1-5级，数字越大颜色越深
            color_map = {
                1: '#e6f7ff',  # 最浅蓝色
                2: '#bae7ff',
                3: '#69c0ff',
                4: '#1890ff',
                5: '#0050b3'  # 最深蓝色
            }

            # ha_grade 到 level 的映射
            ha_grade_to_level = {
                'A1': 1,
                'A2': 2,
                'A3': 3,
                'A4': 4,
                'A5': 5
            }

            for app in apps:
                # 查找所有匹配的巡检配置（可能有多个）
                patrol_configs = PatrolAppConfig.query.filter_by(app_name=app.en_short_name).all()

                # 获取所有匹配的 patrol_name
                patrol_names = [config.patrol_name for config in patrol_configs] if patrol_configs else []

                # 确定 level - 根据 ha_grade 映射
                level = ha_grade_to_level.get(app.ha_grade, 1)
                color = color_map.get(level, '#e6f7ff')

                # 使用模型定义的数据结构
                system_data = {
                    'id': app.service_catalog,
                    'name': app.en_short_name,  # 使用英文简称
                    'color': color,
                    'remark': app.service_name,  # 存放 service_name
                    'type': app.importance_grade,  # 直接使用原始值
                    'level': level,
                    'patrol_names': patrol_names  # 巡检配置名称数组
                }

                systems.append(system_data)

            return format_response(data={'systems': systems})

        except Exception as e:
            return format_response(result=1, result_text=f'获取应用系统概览失败: {str(e)}'), 500


# ========================== API 接口 ==========================

# 在现有的 API 接口后面添加以下路由

@ns_patrol_board.route('/app_main_ball')
class AppMainBallResource(Resource):
    @ns_patrol_board.doc(description='获取应用主图小球数据')
    @ns_patrol_board.marshal_with(main_ball_response_model)
    # @jwt_required()
    def get(self):
        """获取应用主图小球数据"""
        try:
            # 统计总的应用数量
            total_apps_count = db.session.query(func.count(KmsAppInfo.service_catalog)).scalar() or 0

            # 按开发部门分组统计
            dept_stats = db.session.query(
                KmsAppInfo.dev_org,
                func.count(KmsAppInfo.service_catalog).label('count')
            ).group_by(KmsAppInfo.dev_org).all()

            # 构建部门明细列表
            items = []
            for dept_stat in dept_stats:
                dev_department = dept_stat.dev_org if dept_stat.dev_org else '未分配部门'
                items.append({
                    'devDepartment': dev_department,
                    'total': dept_stat.count,
                    'exception': 0  # 暂时都设为0
                })

            # 构建返回数据
            data = {
                'overview': {
                    'mainDepartment': '上海维护',
                    'total': total_apps_count
                },
                'item': items
            }

            return {
                'message': {
                    'result': 0,
                    'result_text': '获取主图小球数据成功',
                    'data': data
                }
            }

        except Exception as e:
            return {
                'message': {
                    'result': 1,
                    'result_text': f'获取主图小球数据失败: {str(e)}',
                    'data': None
                }
            }, 500


# ========================== API 接口 ==========================

# 在现有的 API 接口后面添加以下路由

@ns_patrol_board.route('/app_main_harank')
class AppMainHaRankResource(Resource):
    @ns_patrol_board.doc(description='获取应用HA等级排名数据')
    @ns_patrol_board.marshal_with(ha_rank_response_model)
    # @jwt_required()
    def get(self):
        """获取应用HA等级排名数据"""
        try:
            # 按ha_grade字段分组统计 - 使用括号避免换行问题
            ha_stats = (
                db.session.query(
                    KmsAppInfo.ha_grade,
                    func.count(KmsAppInfo.service_catalog).label('count')
                )
                .filter(KmsAppInfo.ha_grade.isnot(None))
                .group_by(KmsAppInfo.ha_grade)
                .all()
            )

            # 构建HA等级排名列表
            ha_rank_list = []
            for ha_stat in ha_stats:
                if ha_stat.ha_grade:  # 确保ha_grade不为空
                    ha_rank_list.append({
                        'title': ha_stat.ha_grade,
                        'value': ha_stat.count
                    })

            # 按title排序（可选，如果需要特定的排序顺序）
            # ha_rank_list.sort(key=lambda x: x['title'])

            return {
                'message': {
                    'result': 0,
                    'result_text': '获取HA等级排名数据成功',
                    'data': ha_rank_list
                }
            }

        except Exception as e:
            return {
                'message': {
                    'result': 1,
                    'result_text': f'获取HA等级排名数据失败: {str(e)}',
                    'data': None
                }
            }, 500
